home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
castools.zip
/
GARBAGEC.C
< prev
next >
Wrap
Text File
|
1990-01-18
|
8KB
|
273 lines
/*
GARBAGEC.C Function PbGarbageCollect: eliminates the blank areas of a
phonebook file.
This function reduces to 0 the unused bytes in a phonebook.
INPUT: Name of phonebook file to process.
OUTPUT: If successful, returns 1. Otherwise sets Pberrno and returns 0.
*/
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <io.h>
#include <phonebk.h>
#include <ctype.h>
#include <dos.h>
int pascal PbGarbageCollect(char *PbFilename)
{
int retval = 0; /* default (failed) return value */
PB *SourcePb = NULL,
*NewPb = NULL;
long PbSize, unused, avail;
int filenum;
LONGWORD clusters,
sectors,
bytes, /* need these temp's to prevent integer overflow */
next_offset;
struct diskfree_t diskspace; /* for call to _dos_getdiskfree */
unsigned drive; /* for call do _dos_getdiskfree */
int i, j; /* loop counters */
size_t red, writ; /* returns for fread() and fwrite() */
char *temp_name = NULL; /* tmpnam() allocates space for this */
LONGWORD *offsets = NULL; /* will hold 1000 bytes at a time of offset array */
fpos_t source_pos, /* for pushing and popping fpos in sourcePb */
o_dest_pos, /* for pushing and popping fpos in destPb's offsets */
e_dest_pos; /* for pushing and popping fpos in destPb's entries */
WORD entry_size,
next_entry_size;
char *entry_buffer = NULL;
Pberrno = 0; /* Initially, always reset */
/* First, check params */
if (PbFilename == NULL) {
Pberrno = INVALIDPARAMETER;
return(NULL);
}
/* Open the named phonebook */
SourcePb = PbOpenPhonebook(NULL, PbFilename);
if (!SourcePb) {
return(0); /* PbOpenPhonebook has set Pberrno */
}
/* We need to know: size of the phonebook to clean,
# of unused (garbage) bytes in that phonebook,
# of bytes available on disk,
# of bytes as a safety margin. */
filenum = fileno(SourcePb->fp);
PbSize = filelength(filenum);
if (PbSize == -1L) {
goto closeup;
}
unused = SourcePb->header.FreeBytes;
/* Determine the drive number for call to _dos_getdiskfree */
if (PbFilename[1] == ':') {
PbFilename[0] = toupper(PbFilename[0]);
drive = PbFilename[0] - 'A' + 1;
}
else drive = 0;
if (_dos_getdiskfree(drive, &diskspace)) {
goto closeup;
}
avail = (clusters = diskspace.avail_clusters) *
(sectors = diskspace.sectors_per_cluster) *
(bytes = diskspace.bytes_per_sector);
/* If not enough diskspace for operation, set Pberrno and get out */
if (PbSize - unused > avail - DISKSPACEMARGIN) {
Pberrno = OUTOFDISKSPACE;
goto closeup;
}
/* Create a new phonebook with a temporary name, and copy entries into it */
temp_name = tmpnam(NULL);
NewPb = PbCreatePhonebook(NULL, temp_name);
if (!NewPb) {
goto closeup; /* PbCreatePhonebook has set Pberrno */
}
if (fseek(SourcePb->fp, 160L, SEEK_SET)) {
Pberrno = FSEEKERROR;
goto closeup;
}
if (fseek(NewPb->fp, 160L, SEEK_SET)) {
Pberrno = FSEEKERROR;
goto closeup;
}
if (fgetpos(NewPb->fp, &o_dest_pos)) { /* save position in offset array */
goto closeup;
}
if (fseek(NewPb->fp, 4160L, SEEK_SET)) { /* get ready for copying 1st entry */
Pberrno = FSEEKERROR;
goto closeup;
}
if (fgetpos(NewPb->fp, &e_dest_pos)) { /* save position in entry section */
goto closeup;
}
next_offset = 4160L; /* offset of next entry that goes in */
entry_buffer = (char *)malloc(entry_size = sizeof(PBEFIXED));
if (!entry_buffer) {
Pberrno = OUTOFMEM;
goto closeup;
}
offsets = (LONGWORD *)malloc(1000);
if (!offsets) {
Pberrno = OUTOFMEM;
goto closeup;
}
/* Read and process the 4K offset array, 1K at a time */
for (i=0; i<4; i++) {
red = fread(offsets, sizeof(LONGWORD), 250, SourcePb->fp);
if (red != 250) {
Pberrno = CANTREAD;
goto closeup;
}
if (fgetpos(SourcePb->fp, &source_pos)) { /* save pos in source */
goto closeup;
}
if (fsetpos(NewPb->fp, &e_dest_pos)) { /* go to last position in entries*/
goto closeup;
}
/* For each 1/4 of the offset array, scan it for non-NULL entries */
for (j=0; j<250; j++) {
if (offsets[j]) {
NewPb->header.entries++;
/* Get the entry in two reads: 1st, the fixed part, then the rest */
if (fseek(SourcePb->fp, offsets[j], SEEK_SET)) {
Pberrno = FSEEKERROR;
goto closeup;
}
red = fread(entry_buffer, 1, sizeof(PBEFIXED), SourcePb->fp);
if (red != sizeof(PBEFIXED)) {
Pberrno = CANTREAD;
goto closeup;
}
/* Reallocate the entry_buffer only if new entry is larger than last */
next_entry_size = ((PBEFIXED *)entry_buffer)->length;
if (entry_size < next_entry_size) {
entry_buffer = (char *)realloc(entry_buffer, next_entry_size);
if (!entry_buffer) {
Pberrno = OUTOFMEM;
goto closeup;
}
}
entry_size = next_entry_size;
red = fread(entry_buffer + sizeof(PBEFIXED), 1,
entry_size - sizeof(PBEFIXED),
SourcePb->fp);
if (red != entry_size - sizeof(PBEFIXED)) {
Pberrno = CANTREAD;
goto closeup;
}
/* Now copy that entry to end of new phonebook, setting the new offset*/
offsets[j] = next_offset;
next_offset += entry_size;
writ = fwrite(entry_buffer, 1, entry_size, NewPb->fp);
if (writ != entry_size) {
Pberrno = CANTWRITE;
goto closeup;
}
} /* end: if (offsets[j]) */
} /* end: for all 250 offsets in this 1/4 */
if (fgetpos(NewPb->fp, &e_dest_pos)) { /* save position for entries */
goto closeup;
}
if (fsetpos(NewPb->fp, &o_dest_pos)) { /* go to last pos in offsets */
goto closeup;
}
/* Write the updated 1/4 section of the offset array */
writ = fwrite(offsets, sizeof(LONGWORD), 250, NewPb->fp);
if (writ != 250) {
Pberrno = CANTWRITE;
goto closeup;
}
if (fgetpos(NewPb->fp, &o_dest_pos)) { /* save pos in offsets */
goto closeup;
}
if (fsetpos(SourcePb->fp, &source_pos)) { /* return to pos for entries */
goto closeup;
}
} /* end of 4 reads of 1K each */
/* If # of records in new phonebook don't match # of records in old, error */
if (NewPb->header.entries != SourcePb->header.entries) {
Pberrno = INCONSISTENTPBH; /* this is a warning only */
}
/* One more detail: have to copy the header of the source Pb onto the copy */
rewind(NewPb->fp);
SourcePb->header.FreeBytes = 0; /* the only field different */
writ = fwrite(&SourcePb->header, 1, sizeof(PBH), NewPb->fp);
if (writ != sizeof(PBH)) {
Pberrno = CANTWRITE;
goto closeup;
}
/* If we've reached here, all is well: out with the old, in with the new! */
/* First, close up the files and null out the phonebook ptrs */
if (fclose(SourcePb->fp)) {
Pberrno = CANTCLOSE;
}
free(SourcePb);
SourcePb = NULL;
if (fclose(NewPb->fp)) {
Pberrno = CANTCLOSE;
}
free(NewPb);
NewPb = NULL;
/* Finally, delete the old and rename the new to the old name */
if (remove(PbFilename)) {
goto closeup;
}
if (rename(temp_name, PbFilename)) {
goto closeup;
}
retval = 1; /* Success! */
closeup:
if (temp_name) {
free(temp_name);
}
if (entry_buffer) {
free(entry_buffer);
}
if (offsets) {
free(offsets);
}
if (SourcePb) {
if (fclose(SourcePb->fp)) {
Pberrno = CANTCLOSE;
}
free(SourcePb);
}
if (NewPb) {
if (fclose(NewPb->fp)) {
Pberrno = CANTCLOSE;
}
free(NewPb);
}
return(retval);
}